﻿#include "stdafx.h"
#ifdef LK_SOUND_SOUDBUFFER_
namespace LK
{
	namespace Sound
	{
		index_t SoundBuffer::DefaultSize = 10240;//默认是10k的缓冲块
		SoundBuffer::SoundBuffer(index_t size)//创建一个大小为size字节的缓存块
        :LK::Collection::DefaultArray<unsigned char>(size, (unsigned char*)0)
        {
            readingPosition=0;
            writingPosition=0;
            sizeBefore=0;
            sizeAfter=0;
            sizeBeforeMinimum=size / 4;
            isReading=false;
            isWriting=false;
            isResizing=false;
            isRollbacking=false;
            readNothing=false;
            writeNothing=false;
        }
		SoundBuffer::~SoundBuffer()//虚析构函数
		{
		}
		//调整缓存块大小并尽量保存向后的数据
		index_t SoundBuffer::Resize(index_t size)
		{
		START:;
			tc.Lock();
			if (isResizing)
			{
				tc.UnLock();
				Sleep(0);
				goto START;
			}
			tc.UnLock();
			while (isReading || isWriting || isRollbacking)Sleep(0);
			//更改过程不需要同步，因为此时其它操作都被挂起
			LK::Collection::DefaultArray<unsigned char> pdata(size);
			index_t tmp = Length ? Length - (readingPosition%Length + Length) % Length : 0;
			if (tmp > sizeAfter)tmp = sizeAfter;
			if (tmp > size)tmp = size;
			Memory::Copy(pdata, data + (readingPosition%Length + Length) % Length, tmp);
			sizeAfter = size < sizeAfter ? size : sizeAfter;
			if (tmp<sizeAfter)
			{
				Memory::Copy(pdata + tmp, data + ((readingPosition + tmp) % Length + Length) % Length, sizeAfter - tmp);
			}
			writingPosition = sizeAfter;
			readingPosition = 0;
			sizeBefore = 0;
			LK::Collection::DefaultArray<unsigned char>::SwapWith(pdata);
			isResizing = false;
			if (sizeBeforeMinimum>size / 2)sizeBeforeMinimum = size / 2;
			return size;
		}
		//设置预留的后退空间
		void SoundBuffer::SetMinimumSizeBefore(size_t size)
		{
			if (size <= (size_t)Length / 2)sizeBeforeMinimum = size;
		}
		//重置除缓存大小外的参数
		void SoundBuffer::Reset()//采用调整大小的标记，排斥读写
		{
		START:;
			tc.Lock();
			if (isResizing)
			{
				tc.UnLock();
				Sleep(0);
				goto START;
			}
			tc.UnLock();
			while (isReading || isWriting || isRollbacking)Sleep(0);
			//操作
			readingPosition = 0;//更改过程不需要同步，因为此时其它操作都被挂起
			writingPosition = 0;
			sizeBefore = 0;
			sizeAfter = 0;
			isResizing = false;
		}
		//获取可向后读取字节数
		index_t SoundBuffer::GetReadable()const
		{
			return sizeAfter;
		}
		//获取可向后写入字节数
		index_t SoundBuffer::GetWriteable()const
		{
			const_cast<SoundBuffer*>(this)->tc.Lock();
			index_t tmp = Length - sizeAfter - sizeBeforeMinimum;
			tmp = (tmp > Length - sizeAfter - sizeBefore) ? tmp : (Length - sizeAfter - sizeBefore);
			const_cast<SoundBuffer*>(this)->tc.UnLock();
			return tmp;
		}
		//读位置回退,返回实际回退的字节数
		index_t SoundBuffer::Rollback(index_t size)
		{
		START:;
			tc.Lock();
			if (isRollbacking || isResizing)
			{
				tc.UnLock();
				Sleep(0);
				goto START;
			}
			isRollbacking = true;
			tc.UnLock();
			while (isWriting || isReading)Sleep(0);
			if (size > sizeBefore)size = sizeBefore;//更改过程不需要同步，因为此时其它操作都被挂起
			readingPosition -= size;
			sizeBefore -= size;
			sizeAfter += size;

			isRollbacking = false;
			return size;
		}
		//读位置前进,返回实际前进的字节数
		index_t SoundBuffer::Skip(index_t size)
		{
		START1:;
			tc.Lock();
			if (isReading || isResizing || isRollbacking)
			{
				tc.UnLock();
				Sleep(0);
				goto START1;
			}
			isReading = true;//采用读操作标记
			tc.UnLock();
		START2:;
			while (isWriting)Sleep(0);//等待写操作完成
			tc.Lock();//更改过程需要同步，因为此时写操作有可能在进行
			if (isWriting)
			{
				tc.UnLock();
				goto START2;
			}
			if (size > sizeAfter)size = sizeAfter;
			readingPosition += size;
			sizeBefore += size;
			sizeAfter -= size;
			isReading = false;
			tc.UnLock();
			return size;
		}
		//向后读取一定字节数的内容，成功读取时，读取位置将随之后移，内容不足时将一直等待
		Collection::PArray<u8> SoundBuffer::GetAfter(index_t size)
		{
		START1:;
			tc.Lock();
			if (isReading || isResizing || isRollbacking)
			{
				tc.UnLock();
				Sleep(1);
				goto START1;
			}
			isReading = true;//采用读操作标记
			tc.UnLock();
			index_t tmp, i = 0;
			Collection::PArray<u8> outdata(size);
			unsigned char* pdata = outdata;
			while (i < (index_t)size)
			{
				if (!sizeAfter)//无可读内容,等待写入
				{
					if (isRollbacking || isResizing)goto End;
					readNothing = true;
					Sleep(1);
					continue;
				}
				readNothing = false;
				tmp = sizeAfter;
				if (tmp > (index_t)size - i)tmp = size - i;

				if (((readingPosition%Length) + Length) % Length + tmp >= Length)//超出范围
					tmp = Length - ((readingPosition%Length) + Length) % Length;
				Memory::Copy(pdata + i, data + ((readingPosition%Length) + Length) % Length, tmp);
				i += tmp;

			START2:;
				readNothing = true;
				while (isWriting && !writeNothing)Sleep(0);//等待写操作完成
				tc.Lock();//更改过程需要同步，因为此时写操作有可能在进行
				if (isWriting && !writeNothing)
				{
					tc.UnLock();
					goto START2;
				}
				readingPosition += tmp;
				sizeBefore += tmp;
				sizeAfter -= tmp;
				tc.UnLock();
			}
		End:;//结束读取
			readNothing = false;
			isReading = false;//结束读取
			return outdata;
		}
		Collection::PArray<u8> SoundBuffer::GetBefore(index_t size)//向前读取一定字节数的内容，成功读取时，读取位置将随之前移，内容不足时将一直等待
		{
		START1:;
			tc.Lock();
			if (isReading || isResizing || isRollbacking)
			{
				tc.UnLock();
				Sleep(1);
				goto START1;
			}
			isReading = true;//采用读操作标记
			tc.UnLock();
			index_t tmp, i = size;
			Collection::PArray<u8> outdata(size);
			unsigned char* pdata = outdata;
			while (i > 0)
			{
				if (!sizeBefore)//无可读内容,等待写入
				{
					if (isRollbacking || isResizing)goto End;
					readNothing = true;
					Sleep(1);
					continue;
				}
				readNothing = false;
				tmp = sizeBefore;
				if (tmp > i)tmp = i;

				if (((readingPosition%Length) + Length) % Length <= tmp)//超出范围
					tmp = Length - ((readingPosition%Length) + Length) % Length;
				i -= tmp;
				Memory::Copy(pdata + i, data + ((readingPosition%Length) + Length) % Length, tmp);

			START2:;
				while (isWriting && !writeNothing)Sleep(0);//等待写操作完成
				tc.Lock();//更改过程需要同步，因为此时写操作有可能在进行
				if (isWriting && !writeNothing)
				{
					tc.UnLock();
					goto START2;
				}
				readingPosition -= tmp;
				sizeBefore -= tmp;
				sizeAfter += tmp;
				tc.UnLock();
			}
		End:;//结束读取
			readNothing = false;
			isReading = false;//结束读取
			if (i)
			{
				Memory::Move(pdata, pdata + i, size - i);
			}
			outdata.Resize(size - i);
			return outdata;
		}
		/**@brief 向后写入一段数据，若无法写完则一直等待，返回实际写入数量*/
		index_t SoundBuffer::PutAfter(u8 const*xArray, index_t len)
		{
			if (!len)return 0;
		START1:;
			tc.Lock();
			if (isWriting || isResizing || isRollbacking)
			{
				tc.UnLock();
				Sleep(1);
				goto START1;
			}
			if (writingPosition <= readingPosition && sizeAfter)writingPosition = readingPosition + sizeAfter;
			isWriting = true;//采用写操作标记
			tc.UnLock();
			index_t tmp, i = 0;
			while (i < len)
			{
				tc.Lock();
				if (sizeBeforeMinimum + sizeAfter >= Length && sizeBefore + sizeAfter >= Length)// 无可写内容,等待读取
				{
					tc.UnLock();
					if (isRollbacking || isResizing)goto End;
					writeNothing = true;
					Sleep(1);
					continue;
				}
				writeNothing = false;
				if (sizeBefore + sizeAfter >= Length)tmp = Length - sizeAfter - sizeBeforeMinimum;
				else tmp = Length - sizeBefore;
				tc.UnLock();
				if (tmp > len - i)tmp = len - i;

				if (((writingPosition%Length) + Length) % Length + tmp >= Length)//超出范围
					tmp = Length - ((writingPosition%Length) + Length) % Length;
			START2:;
				tc.Lock();//获取过程需要同步，因为此时读操作有可能对数据改动
				if (isReading && !readNothing)//等待读操作完成
				{
					tc.UnLock();
					Sleep(0);
					goto START2;
				}
				if (sizeBefore + tmp + sizeAfter > Length)sizeBefore -= tmp;//向后写入前先减少可向前读取部分
				tc.UnLock();

				Memory::Copy(IArray<u8>::getdata() + ((writingPosition%Length) + Length) % Length, xArray + i, tmp);
				i += tmp;

			START3:
				writeNothing = true;
				tc.Lock();//更改过程需要同步，因为此时写操作有可能在进行
				if (isReading && !readNothing)//等待读操作完成
				{
					tc.UnLock();
					Sleep(0);
					goto START3;
				}
				writingPosition += tmp;
				sizeAfter += tmp;
				tc.UnLock();
			}
		End:;//结束读取
			writeNothing = false;
			isWriting = false;//结束读取
			return i;
		}
		/**@brief 向前写入一段数据，若无法写完则一直等待*/
		index_t SoundBuffer::PutBefore(u8 const*xArray, index_t len)
		{
			if (len == 0)return 0;
		START1:;
			tc.Lock();
			if (isWriting || isResizing || isRollbacking)
			{
				tc.UnLock();
				Sleep(1);
				goto START1;
			}
			if (writingPosition >= readingPosition && sizeBefore)writingPosition = readingPosition - sizeBefore;
			isWriting = true;//采用写操作标记
			tc.UnLock();
			index_t tmp, i = len;
			while (i > 0)
			{
				tc.Lock();
				if (sizeBeforeMinimum + sizeBefore >= Length && sizeBefore + sizeAfter >= Length)// 无可写内容,等待读取
				{
					tc.UnLock();
					if (isRollbacking || isResizing)goto End;
					writeNothing = true;
					Sleep(1);
					continue;
				}
				writeNothing = false;
				if (sizeBefore + sizeAfter >= Length)tmp = Length - sizeBefore - sizeBeforeMinimum;
				else tmp = Length - sizeBefore;
				tc.UnLock();
				if (tmp > i)tmp = i;

				if (((writingPosition%Length) + Length) % Length < tmp)//超出范围
					tmp = ((writingPosition%Length) + Length) % Length;

			START2:;
				tc.Lock();//获取过程需要同步，因为此时读操作有可能对数据改动
				if (isReading && !readNothing)//等待读操作完成
				{
					tc.UnLock();
					Sleep(0);
					goto START2;
				}
				if (sizeBefore + tmp + sizeAfter > Length)sizeAfter -= tmp;//向前写入前先减少可向后读取部分
				tc.UnLock();

				i -= tmp;
				Memory::Copy(IArray<u8>::getdata() + ((writingPosition%Length) + Length) % Length, xArray + i, tmp);

			START3:;
				tc.Lock();//更改过程需要同步，因为此时写操作有可能在进行
				if (isReading && !readNothing)//等待读操作完成
				{
					tc.UnLock();
					Sleep(0);
					goto START3;
				}
				writingPosition -= tmp;
				sizeBefore += tmp;
				tc.UnLock();
			}
		End:;//结束读取
			writeNothing = false;
			isWriting = false;//结束读取
			return len - i;
		}

	}

}
#endif
